package com.ctshk.rpc.finance.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ctshk.common.dto.Result;
import com.ctshk.common.enums.SysApprovalType;
import com.ctshk.common.enums.SystemBusinessType;
import com.ctshk.common.enums.SystemError;
import com.ctshk.common.exception.BusinessException;
import com.ctshk.common.model.PageResponse;
import com.ctshk.common.model.TokenUser;
import com.ctshk.common.utils.EntityUtil;
import com.ctshk.common.utils.SnowflakeIdWorker;
import com.ctshk.rpc.finance.code.AdvanceConstant;
import com.ctshk.rpc.finance.dto.advance.AdvancePaymentRefundDTO;
import com.ctshk.rpc.finance.dto.advance.AdvancePaymentRefundListDTO;
import com.ctshk.rpc.finance.entity.FinanceAdvancePaymentApplySummary;
import com.ctshk.rpc.finance.entity.FinanceAdvancePaymentRefund;
import com.ctshk.rpc.finance.json.FileJson;
import com.ctshk.rpc.finance.mapper.FinanceAdvancePaymentApplySummaryMapper;
import com.ctshk.rpc.finance.mapper.FinanceAdvancePaymentMapper;
import com.ctshk.rpc.finance.mapper.FinanceAdvancePaymentRefundMapper;
import com.ctshk.rpc.finance.req.advance.AdvancePaymentApplyListReq;
import com.ctshk.rpc.finance.req.advance.AdvancePaymentApprovalReq;
import com.ctshk.rpc.finance.req.advance.AdvancePaymentRefundAddReq;
import com.ctshk.rpc.finance.req.advance.AdvancePaymentRefundIdReq;
import com.ctshk.rpc.finance.req.bill.RollBackReq;
import com.ctshk.rpc.finance.service.IFinanceAdvancePaymentRefundService;
import com.ctshk.rpc.system.dto.UserDTO;
import com.ctshk.rpc.system.service.ISysUserService;
import com.ctshk.rpc.workflow.dto.ApprovalCheckDTO;
import com.ctshk.rpc.workflow.dto.ApprovalStartDTO;
import com.ctshk.rpc.workflow.service.ISysApprovalService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

/**
 * <p>
 * 财务退预收款表 服务实现类
 * </p>
 *
 * @author 叶冠峰
 * @since 2021-03-26
 */
@Slf4j
@DubboService
public class FinanceAdvancePaymentRefundServiceImpl extends ServiceImpl<FinanceAdvancePaymentRefundMapper, FinanceAdvancePaymentRefund> implements IFinanceAdvancePaymentRefundService {

    @Autowired
    private FinanceAdvancePaymentApplySummaryMapper advancePaymentApplySummaryMapper;
    @Autowired
    private FinanceAdvancePaymentRefundMapper advancePaymentRefundMapper;
    @Autowired
    private FinanceAdvancePaymentMapper financeAdvancePaymentMapper;

    /*@Autowired
    private RedisTemplate<String, Object> redisTemplate;*/

    @DubboReference
    private ISysApprovalService sysApprovalService;
    @DubboReference
    private ISysUserService sysUserService;


    /**
     * 列表
     *
     * @param req
     * @param currentUser
     * @return
     */
    @Override
    public Result<PageResponse<AdvancePaymentRefundListDTO>> list(AdvancePaymentApplyListReq req, TokenUser currentUser) {
        Page<FinanceAdvancePaymentRefund> page = new Page<>(req.getPageNo(), req.getPageSize());
        QueryWrapper<FinanceAdvancePaymentRefund> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("advance_payment_id",req.getPaymentId());
        queryWrapper.eq("is_deleted",0);
        queryWrapper.orderByDesc("gmt_create");
        Page<FinanceAdvancePaymentRefund> refundPage = advancePaymentRefundMapper.selectPage(page, queryWrapper);
        if (CollectionUtils.isEmpty(refundPage.getRecords())) {
            return Result.success(PageResponse.empty(refundPage.getCurrent()));
        }
        List<AdvancePaymentRefundListDTO> list = new ArrayList<>();
        refundPage.getRecords().forEach(item -> {
            AdvancePaymentRefundListDTO dto = EntityUtil.copy(item,AdvancePaymentRefundListDTO.class);
            //获取申请人
//            UserDTO userDto = (UserDTO) redisTemplate.opsForValue().get(RedisConstants.ACCOUNT_QUERY_KEY + item.getCreateId());
            UserDTO userDto = sysUserService.queryCacheUser(item.getCreateId());
            if (userDto != null){
                dto.setApplyUserDept(userDto.getDept());
                dto.setApplyUserName(userDto.getCnName());
            }
            list.add(dto);
        });
        PageResponse<AdvancePaymentRefundListDTO> result = new PageResponse<>(list,
                refundPage.getCurrent() == 1,
                refundPage.getTotal() <= (refundPage.getCurrent() * refundPage.getSize()),
                refundPage.getTotal(),
                refundPage.getCurrent(),
                refundPage.getSize());
        return Result.success(result);
    }

    /**
     * 申请
     *
     * @param req
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result add(AdvancePaymentRefundAddReq req) {
        //查询汇总
        QueryWrapper<FinanceAdvancePaymentApplySummary> summaryQueryWrapper = new QueryWrapper<>();
        summaryQueryWrapper.eq("advance_payment_id",req.getPaymentId());
        summaryQueryWrapper.eq("is_deleted",0);
        FinanceAdvancePaymentApplySummary summary = advancePaymentApplySummaryMapper.selectOne(summaryQueryWrapper);
        if (summary == null){
            throw new BusinessException(SystemError.FINANCE_ADVANCE_17002);
        }
        //金额判断
        if (summary.getMoneyAmount().compareTo(req.getRefundMoneyAmount()) < 0){
            throw new BusinessException(SystemError.FINANCE_ADVANCE_17003, AdvanceConstant.MONEY_AMOUNT);
        }
        if (summary.getUnavailableAmount().compareTo(req.getRefundUnavailableAmount()) < 0){
            throw new BusinessException(SystemError.FINANCE_ADVANCE_17003, AdvanceConstant.UNAVAILABLE_AMOUNT);
        }
        //新增退款申请记录
        FinanceAdvancePaymentRefund refund = EntityUtil.copy(req,FinanceAdvancePaymentRefund.class);
        refund.setId(SnowflakeIdWorker.nextId());
        refund.setAdvancePaymentId(req.getPaymentId());
        refund.setSupplierId(summary.getSupplierId());
        //退預收金額-退不可用金額=退可用金額
        BigDecimal availableAmount = req.getRefundMoneyAmount().subtract(req.getRefundUnavailableAmount());
        refund.setRefundAvailableAmount(availableAmount);
        refund.setApprovalStatus(req.getType());
        //附件
        List<FileJson> fileJson = req.getFileJson();
        if (fileJson != null && fileJson.size() > 0){
            String jsonString = JSONArray.toJSONString(fileJson);
            refund.setFileJson(jsonString);
        }
        refund.setCreateId(req.getUserId());
        refund.setGmtCreate(LocalDateTime.now());
        boolean save = save(refund);
        if (!save){
            throw new BusinessException(SystemError.SYS_437);
        }
        if (Objects.equals(req.getType(),2)){
            //发起审批
            Long approvalId = startApproval(refund.getId(), refund.getId(), req.getUserId());
            refund.setApprovalId(approvalId);
            boolean update = updateById(refund);
            if (!update){
                throw new BusinessException(SystemError.SYS_437);
            }
        }
        return Result.success(refund.getId());
    }

    /**
     * 提交
     *
     * @param req
     * @return
     */
    @Override
    public Result commit(AdvancePaymentRefundIdReq req) {
        //退预收记录
        FinanceAdvancePaymentRefund refund = getById(req.getRefundId());
        if (refund == null || Objects.equals(refund.getIsDeleted(),1)){
            throw new BusinessException(SystemError.FINANCE_ADVANCE_17004);
        }
        if (!Objects.equals(refund.getApprovalStatus(),1)){
            throw new BusinessException(SystemError.FINANCE_ADVANCE_17005);
        }
        refund.setApprovalStatus(2);
        refund.setModifiedId(req.getUserId());
        //发起审批
        Long approvalId = startApproval(refund.getId(), refund.getAdvancePaymentId(), req.getUserId());
        refund.setApprovalId(approvalId);
        boolean bl = updateById(refund);
        if (!bl){
            throw new BusinessException(SystemError.SYS_437);
        }
        return Result.success(refund.getId());
    }

    /**
     * 详情
     *
     * @param req
     * @return
     */
    @Override
    public Result<AdvancePaymentRefundDTO> detail(AdvancePaymentRefundIdReq req) {
        //退预收记录详情
        AdvancePaymentRefundDTO dto = advancePaymentRefundMapper.queryDetail(req.getRefundId());
        if (dto == null){
            throw new BusinessException(SystemError.FINANCE_ADVANCE_17004);
        }
        //获取申请人
//        UserDTO userDto = (UserDTO) redisTemplate.opsForValue().get(RedisConstants.ACCOUNT_QUERY_KEY + dto.getCreateId());
        UserDTO userDto = sysUserService.queryCacheUser(dto.getCreateId());
        if (userDto != null){
            dto.setApplier(userDto.getDept());
            dto.setDeptName(userDto.getCnName());
        }
        //附件
        if (StringUtils.isNotBlank(dto.getFileJson())){
            List<FileJson> fileJsonList = JSON.parseArray(dto.getFileJson(), FileJson.class);
            dto.setFileJsonList(fileJsonList);
        }
        return Result.success(dto);
    }

    /**
     * 审批
     *
     * @param req
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result approval(AdvancePaymentApprovalReq req) {
        //获取退预收记录
        QueryWrapper<FinanceAdvancePaymentRefund> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("approval_id",req.getApprovalId());
        queryWrapper.eq("is_deleted",0);
        FinanceAdvancePaymentRefund refund = advancePaymentRefundMapper.selectOne(queryWrapper);
        if (refund == null){
            throw new BusinessException(SystemError.FINANCE_ADVANCE_17004);
        }
        //状态判断
        if (!Objects.equals(refund.getApprovalStatus(),2)){
            throw new BusinessException(SystemError.FINANCE_ADVANCE_17005);
        }
        //更新退预收记录
        refund.setApprovalStatus(req.getType());
        refund.setModifiedId(req.getUserId());
        boolean bl = updateById(refund);
        if (!bl){
            throw new BusinessException(SystemError.SYS_437);
        }
        if (Objects.equals(req.getType(),3)){
            //审批通过
            //查询汇总
            QueryWrapper<FinanceAdvancePaymentApplySummary> summaryQueryWrapper = new QueryWrapper<>();
            summaryQueryWrapper.eq("advance_payment_id",refund.getAdvancePaymentId());
            summaryQueryWrapper.eq("is_deleted",0);
            FinanceAdvancePaymentApplySummary summary = advancePaymentApplySummaryMapper.selectOne(summaryQueryWrapper);
            if (summary == null){
                throw new BusinessException(SystemError.FINANCE_ADVANCE_17002);
            }
            //更新汇总
            summary.setMoneyAmount(summary.getMoneyAmount().subtract(refund.getRefundMoneyAmount()));
            summary.setUnavailableAmount(summary.getUnavailableAmount().subtract(refund.getRefundUnavailableAmount()));
            summary.setAvailableAmount(summary.getAvailableAmount().subtract(refund.getRefundMoneyAmount().subtract(refund.getRefundUnavailableAmount())));
            summary.setRemainingAmount(summary.getAvailableAmount().subtract(summary.getAmountUsed()));
            summary.setModifiedId(req.getUserId());
            int update = advancePaymentApplySummaryMapper.updateById(summary);
            if (update <= 0){
                throw new BusinessException(SystemError.SYS_437);
            }
        }
        Result<ApprovalCheckDTO> check = sysApprovalService.check(req.getApprovalId(), req.getUserId(), req.getType(), req.getComments());
        if (check == null || !check.getData().getIsFinish()){
            throw new BusinessException(SystemError.SYS_437);
        }
        return Result.success(refund.getId());
    }

    /**
     * 撤回审批
     *
     * @param req
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result rollBack(RollBackReq req) {
        //获取退预收记录
        QueryWrapper<FinanceAdvancePaymentRefund> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("approval_id",req.getApprovalId());
        queryWrapper.eq("is_deleted",0);
        FinanceAdvancePaymentRefund refund = advancePaymentRefundMapper.selectOne(queryWrapper);
        if (refund == null){
            throw new BusinessException(SystemError.FINANCE_ADVANCE_17004);
        }
        if (!Objects.equals(refund.getCreateId(),req.getUserId())){
            throw new BusinessException(SystemError.FINANCE_ERROR_17039);
        }
        refund.setApprovalStatus(1);
        refund.setApprovalId(null);
        refund.setModifiedId(req.getUserId());
        int update = advancePaymentRefundMapper.updateById(refund);
        if (update <= 0){
            throw new BusinessException(SystemError.SYS_437);
        }
        Result<ApprovalCheckDTO> check = sysApprovalService.check(req.getApprovalId(), req.getUserId(), 0, null);
        if (check == null || !check.getData().getIsFinish()){
            throw new BusinessException(SystemError.SYS_437);
        }
        return Result.success();
    }


    /**
     * 发起审批流程
     * @param id
     * @param businessId
     * @param userId
     */
    private Long startApproval(Long id, Long businessId, Long userId) {
        Map<String, Object> extendParams = new HashMap<>();
        extendParams.put("id", id);
        try{
            Result<ApprovalStartDTO> approvalResult = sysApprovalService.start(SystemBusinessType.FINANCE.getCode(),
                    SysApprovalType.REFUND_PAYMENT_FINANCE.getCode(), businessId,
                    userId, null, JSON.toJSONString(extendParams));
            if (!approvalResult.isSuccess()) {
                throw new BusinessException(SystemError.CUSTOM_ORDER_4044);
            }
            return approvalResult.getData().getApprovalId();
        }catch (Exception e){
            throw new BusinessException(SystemError.SYS_422);
        }
    }

}
